using Core;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public partial class BundleTool
{
    public const string VERSION_ID = "0.0.1";

    [MenuItem("Mini Tools/Bundle/Android/Build", false)]
    [MenuItem("Assets/Mini Tools/Bundle/Android/Build", false)]
    public static void BuildAndroid()
    {
        if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.Android)
        {
            EditorUtility.DisplayDialog("警告", "当前不是Android平台，无法进行打包", "确定");
            return;
        }

        Build(BuildTarget.Android);
    }

    [MenuItem("Mini Tools/Bundle/WX/Build", false)]
    [MenuItem("Assets/Mini Tools/Bundle/WX/Build", false)]
    public static void BuildWX()
    {
        if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL)
        {
            EditorUtility.DisplayDialog("警告", "当前不是WebGL平台，无法进行打包", "确定");
            return;
        }

        Build(BuildTarget.WebGL);
    }


    [MenuItem("Mini Tools/Bundle/WX/Build Resource", false)]
    [MenuItem("Assets/Mini Tools/Bundle/WX/Build Resource", false)]
    public static void BuildResourceWX()
    {
        //if (EditorUserBuildSettings.activeBuildTarget != BuildTarget.WebGL)
        //{
        //    EditorUtility.DisplayDialog("警告", "当前不是WebGL平台，无法进行打包", "确定");
        //    return;
        //}

        //Build(BuildTarget.WebGL);
        ClearResource();

        MoveOutUselessDir();

        GetGameNames();

        Copy2Resource();
    }

    [MenuItem("Mini Tools/Bundle/WX/Upload to Oss", false)]
    public static void WXUpload2Oss()
    {
        UploadStreaming2Oss(BuildTarget.WebGL);
    }

    private static void Build(BuildTarget target)
    {
        ClearResource();

        GetGameNames();
        SetBaseInfo(target);

        StatisticAssets();
        CheckCircularRely();
        StatisticBundles();

        ClearAllAssetBundleName();
        MarkAllAssetBundleName();
        BundleAssetBundle(target);
        GatherBundleHash();

        Encrypt();
        Copy2Streaming();
    }

    private static List<string> gNames = new();

    private static string buildPath;
    private static string workingPath;
    private static string packagePath;

    public static void GetGameNames()
    {
        gNames.Clear();

        var game_tbl =
            AssetDatabase.LoadAssetAtPath<TblGame>($"Assets/Proj/Games/s_common/Res/Conf/Table/TblGame.asset");
        if (game_tbl == null)
        {
            Debug.LogError("Error! tblgame.asset 不存在");
            return;
        }

        foreach (var game in game_tbl.Confs)
        {
            var gName = $"g_{game.Name}";
            Debug.Log(gName);
            gNames.Add(gName);
        }

        gNames.Add("s_common");
    }

    public static void SetBaseInfo(BuildTarget target)
    {
        buildPath = Path.Combine(Application.dataPath, "../../Build/AssetBundle");
        Utils.File.CreateDirectory(buildPath);

        workingPath = Path.Combine(buildPath, $"Working/{target}");
        Utils.File.CreateDirectory(workingPath);

        packagePath = Path.Combine(buildPath, $"Package/{target}");
        Utils.File.CreateDirectory(packagePath);
    }

    private static void StatisticAssets()
    {
        dicA.Clear();

        foreach (var name in gNames)
        {
            StatisticAssets(name);
        }
    }

    private static void StatisticAssets(string gName)
    {
        var res_path = Path.Combine(Application.dataPath, $"Proj/Games/{gName}/Res/");
        Debug.Log(res_path);
        var files = Utils.File.GetFiles(res_path);
        files.RemoveAll(c => c.EndsWith(".meta"));
        //Debug.Log($"{gName} file cnt = {files.Count}");

        var queue = new Queue<string>();

        foreach (var file in files)
        {
            var asset_path = file[file.IndexOf("Assets")..];
            queue.Enqueue(asset_path);
        }

        var relies_lst = new List<string>();

        while (queue.Count > 0)
        {
            var asset_path = queue.Dequeue();
            var asset = AssetDatabase.LoadAssetAtPath(asset_path, typeof(UnityEngine.Object));
            if (asset == null)
            {
                continue;
            }

            AddAsset(asset_path);

            relies_lst.Clear();
            var relies = AssetDatabase.GetDependencies(asset_path);

            relies_lst.AddRange(relies);
            relies_lst.Remove(asset_path);
            relies_lst.RemoveAll(c => c.EndsWith(".cs"));

            foreach (var relies_path in relies_lst)
            {
                if (relies_path.StartsWith("Assets") == false)
                {
                    continue;
                }

                asset = AssetDatabase.LoadAssetAtPath(relies_path, typeof(UnityEngine.Object));
                if (asset == null)
                {
                    continue;
                }

                AddAsset(relies_path);

                SetAssetRely(asset_path, relies_path);

                queue.Enqueue(relies_path);
            }
        }
    }

    private static bool StatisticBundles()
    {
        dicB.Clear();

        foreach (var pair in dicA)
        {
            var asset = pair.Value;
            SetBundleName(asset);
        }

        return true;
    }

    public static void ClearAllAssetBundleName()
    {
        string[] names = AssetDatabase.GetAllAssetBundleNames();
        for (int i = 0; i < names.Length; i++)
        {
            string[] paths = AssetDatabase.GetAssetPathsFromAssetBundle(names[i]);
            for (int j = 0; j < paths.Length; j++)
            {
                var importor = AssetImporter.GetAtPath(paths[j]);
                importor.assetBundleName = string.Empty;
            }

            AssetDatabase.RemoveAssetBundleName(names[i], true);
        }

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        Debug.Log("AssetBundleName清理完成");
    }

    public static void MarkAllAssetBundleName()
    {
        AssetDatabase.RemoveUnusedAssetBundleNames();

        foreach (var pair in dicA)
        {
            var item = pair.Value;
            AssetImporter importer = AssetImporter.GetAtPath(item.Path);
            importer.assetBundleName = item.Bundle;
            importer.assetBundleVariant = null;
        }

        AssetDatabase.Refresh();

        Debug.Log("AssetBundleName标记完成");
    }

    public static void BundleAssetBundle(BuildTarget target)
    {
        var options = BuildAssetBundleOptions.AppendHashToAssetBundleName |
                      BuildAssetBundleOptions.ChunkBasedCompression |
                      BuildAssetBundleOptions.DisableWriteTypeTree |
                      BuildAssetBundleOptions.None;

        BuildPipeline.BuildAssetBundles(workingPath, options, target);

        Debug.Log("AssetBundle Build 完成");
    }

    public static void GatherBundleHash()
    {
        var files = Utils.File.GetFiles(workingPath);
        files.RemoveAll(c => c.EndsWith(".manifest"));
        files.RemoveAll(c => c.EndsWith(".json"));

        foreach (var path in files)
        {
            var fi = new FileInfo(path);

            var index = fi.Name.LastIndexOf("_");
            if (index < 0)
            {
                continue;
            }

            var hash = fi.Name.Substring(index + 1);
            var bundle_name = fi.Name.Substring(0, index);

            if (dicB.ContainsKey(bundle_name) == false)
            {
                continue;
            }

            var bundle = dicB[bundle_name];
            bundle.Hash = hash;
            bundle.Length = (int)fi.Length;
        }
    }

    private static void Encrypt()
    {
        File.WriteAllText(Path.Combine(workingPath, "res_list.json"), GetResListJson());

        var str = File.ReadAllText(Path.Combine(workingPath, "res_list.json"));
        var encrypt_str = Utils.Crypto.Encrypt(str, "uertyewtruieywty");
        File.WriteAllText(Path.Combine(packagePath, "game.dat"), encrypt_str);

        foreach (var pair in dicB)
        {
            var bundle = pair.Value;
            var tgt_path = Path.Combine(packagePath, bundle.Hash);

            if (File.Exists(tgt_path))
            {
                File.Delete(tgt_path);
            }

            var fs = new FileStream(tgt_path, FileMode.Create);

            var src_path = Path.Combine(workingPath, $"{bundle.Name}_{bundle.Hash}");
            var bytes = File.ReadAllBytes(src_path);

            fs.Write(bytes);

            fs.Flush();
            fs.Close();
        }
    }

    private static void Copy2Streaming()
    {
        var streamingPath = Path.Combine(Application.streamingAssetsPath, "abs");
        Utils.File.DeleteDir(streamingPath);
        Utils.File.CopyFolder(packagePath, streamingPath);

        AssetDatabase.Refresh();

        Debug.Log("AssetBundle Build 完成");
    }

    private static void ClearResource()
    {
        var tgt_path = Path.Combine(Application.dataPath, $"Resources/Games/");

        Utils.File.DeleteDir(tgt_path);

        AssetDatabase.Refresh();

        Debug.Log("Resources Clear 完成");
    }

    private static void MoveOutUselessDir()
    {
        var useless_paths = new string[]
        {
            "Assets/_PreviewDir",
        };

        foreach (var path in useless_paths)
        {
            Utils.File.Rename(path, path + "~");
        }

        AssetDatabase.Refresh();
        Debug.Log("UselessDir Rename 完成");
    }

    private static void Copy2Resource()
    {
        foreach (var g_name in gNames)
        {
            var src_path = Path.Combine(Application.dataPath, $"Proj/Games/{g_name}/Res");
            var tgt_path = Path.Combine(Application.dataPath, $"Resources/Games/{g_name}/Res");
            Utils.File.CopyFolder(src_path, tgt_path);
        }

        var useless_paths = new string[]
        {
            "Assets/Resources/Games/s_common/Res/Fonts",
        };

        foreach (var path in useless_paths)
        {
            Utils.File.DeleteDir(path);
        }

        AssetDatabase.Refresh();

        Debug.Log("Resources Copy 完成");
    }

    private static void UploadStreaming2Oss(BuildTarget buildTarget)
    {
        Debug.Log("Upload2Oss");
        //OssManager.Instance.SwitchOssMode(true);

        //string version_id_path = $"{Global.OssDirPath}/{buildTarget}/VersionId.txt";
        //if (!OssManager.Instance.DoesFileExist(version_id_path))
        //{
        //    Debug.LogError($"{version_id_path} 不存在，请先创建该文件");
        //    return;
        //}

        //var remote_content = OssManager.Instance.GetString(version_id_path, 0, -1);
        //var arr = remote_content.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
        //if (arr.Length > 0)
        //{
        //    var latest_version = arr[arr.Length - 1];
        //    var latest = Core.Version.Parse(latest_version);
        //    var curr = Core.Version.Parse(VersionId);
        //    if (curr <= latest)
        //    {
        //        Debug.LogError($"当前版本号要大于线上版本号，curr:{VersionId}，online:{latest_version}。需要手动处理");
        //        return;
        //    }
        //}
        //else
        //{
        //    Debug.Log("OSS没有版本");
        //    return;
        //}

        //var streamingPath = Path.Combine(Application.streamingAssetsPath, "abs");

        //var di = new DirectoryInfo(streamingPath);
        //var fis = di.GetFiles("*.*", SearchOption.AllDirectories);

        //var m_list = new List<FileInfo>();

        //for (int i = 0; i < fis.Length; i++)
        //{
        //    var f = fis[i];
        //    var lower = f.Name.ToLower();
        //    if (lower.EndsWith(".meta"))
        //    {
        //        continue;
        //    }
        //    var local_path = f.FullName;
        //    var remote_path = local_path.Replace(di.FullName, $"{Global.OssDirPath}/{buildTarget}/ABS");
        //    remote_path = remote_path.Replace("\\", "/");
        //    EditorUtility.DisplayProgressBar("检测", remote_path, i * 1.0f / fis.Length);
        //    bool is_exist = OssManager.Instance.DoesFileExist(remote_path);
        //    if (is_exist == false)
        //    {
        //        m_list.Add(f);
        //        continue;
        //    }
        //    string local_md5;
        //    long local_length;
        //    using (var fs = File.Open(local_path, FileMode.Open))
        //    {
        //        local_md5 = Aliyun.OSS.Util.OssUtils.ComputeContentMd5(fs, fs.Length);
        //        local_length = fs.Length;
        //    }
        //    var oss_md5 = OssManager.Instance.GetFileMD5(remote_path);
        //    var oss_length = OssManager.Instance.GetFileLength(remote_path);

        //    if (local_md5 == oss_md5 && local_length == oss_length)
        //    {
        //        continue;
        //    }
        //    m_list.Add(f);
        //}
        //EditorUtility.ClearProgressBar();

        //if (m_list.Count == 0)
        //{
        //    Debug.LogError("没有资源要提交");
        //    return;
        //}

        //for (int i = 0; i < m_list.Count; i++)
        //{
        //    var f = m_list[i];
        //    var local_path = f.FullName;
        //    var remote_path = local_path.Replace(di.FullName, $"{Global.OssDirPath}/{buildTarget}/ABS");
        //    remote_path = remote_path.Replace("\\", "/");

        //    if (f.Name.ToLower().EndsWith("game.dat"))
        //    {
        //        remote_path = remote_path.Replace("game.dat", $"game.{VersionId}.dat");
        //    }

        //    Debug.LogError($"正在提交：{remote_path}");

        //    EditorUtility.DisplayProgressBar($"正在提交({i}/{m_list.Count})", remote_path, i * 1.0f / m_list.Count);

        //    OssManager.Instance.UploadFile(remote_path, local_path);
        //}

        //EditorUtility.ClearProgressBar();
        //OssManager.Instance.AppendString(version_id_path, VersionId);
    }
}
